from sys import argv
from math import sin, cos
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *

class MyPyOpenGLTest:
    def __init__(self, width=640, height=640, title='半透明效果'):
        glutInit(len(argv), argv)
        glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)
        glutInitWindowSize(width, height)
        glutInitWindowPosition(350, 200)
        self.window = glutCreateWindow(title.encode('gbk'))
        glutDisplayFunc(self.draw)
        glutSpecialFunc(self.special_key)
        glutReshapeFunc(self.reshape)
        # 绿色球的透明度
        self.sphere_alpha = 0.4
        # 球体x、y坐标
        self.sphere_x, self.sphere_y = 1, 1

        glClearColor(0, 0, 0, 1)
        # 使用深度测试
        glEnable(GL_DEPTH_TEST)
        # 材质跟踪颜色
        glEnable(GL_COLOR_MATERIAL)

        glEnable(GL_BLEND)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
        
        glShadeModel(GL_SMOOTH)
        # 对点进行反走样，会显示为圆形的点
        glEnable(GL_POINT_SMOOTH)
        glEnable(GL_LINE_SMOOTH)
        glEnable(GL_POLYGON_SMOOTH)
        glHint(GL_POINT_SMOOTH_HINT, GL_NICEST)
        glHint(GL_LINE_SMOOTH_HINT, GL_NICEST)
        glHint(GL_POLYGON_SMOOTH_HINT, GL_FASTEST)

        # 设置光照效果
        glLightfv(GL_LIGHT0, GL_POSITION, (0.5, 0.5, 4, 0))
        glEnable(GL_LIGHTING)
        glEnable(GL_LIGHT0)

        # 设置物体表面材质属性，对环境光、漫反射、镜面反射光的反应以及反光系数
        glMaterialfv(GL_FRONT, GL_AMBIENT, (0.15, 0.23, 0.13))
        glMaterialfv(GL_FRONT, GL_DIFFUSE, (0.6, 0.2, 0.3))
        glMaterialfv(GL_FRONT, GL_SPECULAR, (0.71, 0.6, 0.73))
        glMaterialfv(GL_FRONT, GL_SHININESS, 100)

        glMatrixMode(GL_PROJECTION)
        gluPerspective(45, width/height, 0.1, 10)
        glMatrixMode(GL_MODELVIEW)

    def special_key(self, key, x, y):
        if key == GLUT_KEY_UP:
            # 上下移动
            self.sphere_y = self.sphere_y + 0.05
        elif key == GLUT_KEY_DOWN:
            self.sphere_y = self.sphere_y - 0.05
        elif key == GLUT_KEY_LEFT:
            # 左右移动
            self.sphere_x = self.sphere_x - 0.05
        elif key == GLUT_KEY_RIGHT:
            self.sphere_x = self.sphere_x + 0.05
        elif key == GLUT_KEY_PAGE_UP:
            self.sphere_alpha = min(1, self.sphere_alpha + 0.05)
        elif key == GLUT_KEY_PAGE_DOWN:
            self.sphere_alpha = max(0, self.sphere_alpha - 0.05)
        # 每次按键之后强制刷新屏幕
        glutPostRedisplay()

    def reshape(self, w, h):
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        ratio = w / h
        glViewport(0, 0, w, h)
        # 使用正交投影，设置坐标系显示范围
        gluOrtho2D(-6, 6, -6*ratio, 6*ratio)
        
    def draw(self):
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()

        glPushMatrix()
        glTranslatef(0, 0, -1.5)
        glColor4f(1, 0, 0, 1)
        glutSolidTorus(1, 2, 30, 30)
        glPopMatrix()

        glPushMatrix()
        glTranslatef(self.sphere_x, self.sphere_y, 0)
        glColor4f(0, 1, 0, self.sphere_alpha)
        glutSolidSphere(1, 30, 30)
        glPopMatrix()

        glutSwapBuffers()

    # 消息主循环
    def mainloop(self):
        glutMainLoop()

if __name__ == '__main__':
    MyPyOpenGLTest().mainloop()
